---
sidebar_position: 0
---
import CodeBlock from '@theme/CodeBlock';
import BrowserOnly from '@docusaurus/BrowserOnly'
import { FrameworkTabs } from '../components/framework-tabs'
import { PropsTable } from '@site/src/components/PropsTable'
import { generateDataRecords, generateTimeSeries } from '../utils/data'
import { XYWrapper, XYWrapperWithInput } from '../wrappers'
import { Axis } from '@unovis/ts'

export const axisProps = (n=10) => ({
  name: "Axis",
  data: generateDataRecords(n),
  type: "x",
  height: 100,
  hiddenProps: { gridLine: false },
  configKey: "xAxis",
});

export const multiProps = (xProps, yProps) => ({
  ...axisProps(),
  ...xProps,
  components: [
    { name: "Axis", key: "yAxis", props: {type: "y", ...yProps } },
  ],
  showContext: "container"
})

### Basic configuration
The _Axis_ component has been designed to work together with _XY Container_. The minimal _Axis_ configuration looks like:
<XYWrapper {...axisProps()}/>

### Axis Types
_Axis_ supports two `AxisType` properties to bind to your data: `AxisType.X` and `AxisType.Y`. You can also simply provide the string `"x"` or `"y"`.

#### AxisType.X
<XYWrapper {...axisProps()}/>

#### AxisType.Y
<XYWrapper {...axisProps()} type="y" configKey="yAxis"/>

### Axis Position
You can change the position of your axis with a `Position` type or a string equivalent: `"top"`, `"right"`, `"bottom"`, or `"left"`.

<XYWrapper {...multiProps({ position: 'top', label: 'X'}, {position: "right", label: "Y"})}/>

:::note

Note: An X _Axis_ can only accept the values `Position.Bottom` (default) and `Position.Top` and a Y _Axis_ can only accept `Position.Left` (default) and `Position.Right`.
The default will be used in the case of an invalid position argument.

:::

## Labeling
### Axis Label
You can provide a string to label your axes with the `label` property:
<XYWrapperWithInput {...axisProps()} height={75} inputType="text" defaultValue="Label" property="label"/>

### Label Font Size
Change the label size (in pixels) with the `labelFontSize` property.
<XYWrapperWithInput {...axisProps()} inputType="range" label="Label" defaultValue={30} property="labelFontSize"/>

### Label Color
Change the label color with the `labelColor` property.
<XYWrapperWithInput {...axisProps()} inputType="color" label="Label" defaultValue={'#1acb9a'} property="labelColor"/>

### Label Margin
The spacing between the label and the axis itself can be set with the `labelMargin` property:
<XYWrapperWithInput {...axisProps()} label="Label" inputType="range" inputProps={{ min: 0, max: 50, step: 1}} defaultValue={5} property="labelMargin"/>

### Grid Line
You can enable or disable the visibility of the _Axis_ grid line with the `gridLine` property.
<XYWrapperWithInput
  {...axisProps()}
  inputType="checkbox"
  defaultValue={true}
  property="gridLine"
  hiddenProps={{}}
/>

### Axis Domain Line
You can enable or disable the visibility of the axis domain line with the `domainLine` property.
<XYWrapperWithInput {...axisProps()} label="Label" inputType="checkbox" defaultValue={true} property="domainLine"/>

### Providing Data to _Axis_
If you use the _Axis_ component alone, without other xy-components, you'll need to provide an `x` accessor or `y` accessors to populate the axis values.
Consider the following example with a single axis and a data array with x values in the range `0 < x < 10`:

<XYWrapper {...axisProps()} x={d => d.x} showContext="full"/>
Another example:

```ts
const x = (d: DataRecord) => d.x * 100
```
<XYWrapper {...axisProps()} x={d => d.x * 100} excludeTabs/>

## Tick Configuration
The _Axis_ component supports a wide variety of tick customization options

### Tick Line
You can remove tick labels from your axis by setting the `tickLine` property to false:
<XYWrapperWithInput {...axisProps()} inputType="checkbox" defaultValue={false} property="tickLine"/>

### Tick Label Font Size
To change the font size for the tick labels, you provide the `tickTextFontSize` property with a CSS string.
<XYWrapperWithInput {...axisProps()} inputType="text" defaultValue={'50px'} property="tickTextFontSize"/>

### Tick Label Color
You can change the color of the tick labels with the `tickTextColor` property.
<XYWrapperWithInput {...axisProps()} inputType="color" defaultValue={'#1acb9a'} property="tickTextColor"/>

### Tick Label Format
You can customize how ticks are formatted using the `tickFormat` property and a label formatter function.
The following example uses Javascript's built-in Date formatter function `toDateString()`.
<XYWrapper {...axisProps()} data={generateTimeSeries(10)} x={d => d.timestamp} tickFormat={d=> new Date(d).toDateString()}/>

### Label Alignment
Change the tick's label alignment with respect to the tick marker using `tickTextAlign` property with a TextAlign value: `TextAlign.Left`, `TextAlign.Right` or `TextAlign.Center`.
<XYWrapperWithInput
  {...axisProps()}
  inputType="select"
  data={generateTimeSeries(10)}
  hiddenProps={{gridLine: false, x: d => d.timestamp, tickFormat: d=> new Date(d).toDateString()}}
  options={['right', 'center', 'left']}
  property="tickTextAlign"/>

### Label Rotation
Change the tick's label angle using `tickTextAngle` property with a number value. Use this variable along with `tickTextAlign` to make sure the tick label displays as desired.
<XYWrapperWithInput
  {...axisProps()}
  tickTextAlign="left"
  inputType="select"
  data={generateTimeSeries(10)}
  hiddenProps={{gridLine: false, x: d => d.timestamp, tickFormat: d=> new Date(d).toDateString()}}
  defaultValue={15}
  options={[15, 30, 45]}
  property="tickTextAngle"/>

### Label Width
To limit the width of the tick labels (in pixels), you can use the `tickTextWidth` property.
<XYWrapperWithInput
  {...axisProps()}
  inputType="number"
  defaultValue={50}
  property="tickTextWidth"
  data={generateTimeSeries(10)}
  hiddenProps={{gridLine: false, x: d => d.timestamp, tickFormat: d=> new Date(d).toDateString()}}
/>

### Label Fit Mode
_Axis_ accepts the following values for the `tickTextFitMode` property: `FitMode.Wrap` or `FitMode.Trim`. This determines how the axis will
handle tick text overflow. The following example showcases the previous example using `"trim"` instead of `"wrap"`.
<XYWrapperWithInput inputType="select"
  {...axisProps()}
  tickTextWidth={10}
  data={generateTimeSeries(10)}
  hiddenProps={{gridLine: false, x: d => d.timestamp, tickFormat: d=> new Date(d).toDateString(), tickTextTrimType:"end"}}
  options={['trim', 'wrap']}
  property="tickTextFitMode"/>

### Label Trim Type
When a tick label becomes too long, and you want to trim it, you can customize the trimming method with the `tickTextTrimType` property.
_Axis_ accepts a `TrimMode` or a string. For example, when we configure `tickTextTrimType` to `TrimMode.Start`, we can see the start of the label gets cut off instead of the middle.
<XYWrapperWithInput inputType="select"
  {...axisProps()}
  tickTextFitMode="trim"
  tickTextWidth={30}
  data={generateTimeSeries(10)}
  hiddenProps={{gridLine: false, x: d => d.timestamp, tickFormat: d=> new Date(d).toDateString()}}
  options={['start', 'middle', 'end']}
  property="tickTextTrimType"/>

### Force Word Break
In addition, you can enable a forced word break for overflowing tick labels with the `tickTextForceWordBreak` property.
<XYWrapperWithInput
  {...axisProps()}
  inputType="checkbox"
  tickTextWidth={10}
  data={generateTimeSeries(10)}
  hiddenProps={{gridLine: false, x: d => d.timestamp, tickFormat: d=> new Date(d).toDateString(), tickTextTrimType:"end"}}
  defaultValue={true}
  property="tickTextForceWordBreak"/>

### Text Separator
_Axis_ accepts a `string` or `string[]` value for `tickTextSeparator` property. This will allow tick labels to be separated by custom values in the case of overflow.
Note: this only takes effect when `FitMode.Wrap` is enabled and `tickTextWidth` is defined.
<XYWrapperWithInput
  {...axisProps()}
  inputType="text"
  tickTextWidth={10}
  data={generateTimeSeries(3)}
  hiddenProps={{gridLine: false, x: d => d.timestamp, tickFormat: (d,i)=> new Date(d).toUTCString()}}
  defaultValue=","
  property="tickTextSeparator"/>

### Custom Number of Ticks
By default, the _Axis_ component provides an optimal number of ticks displayed based on the component's size. You can alter the tick count to your liking using the `numTicks` property.

:::note

The specified count is only a hint, the axis can have more or fewer ticks depending on the data

:::

<XYWrapperWithInput
  {...axisProps()}
  inputType="range"
  inputProps={{ min: 1, max: 30}}
  defaultValue={20}
  property="numTicks"/>

### Display Only Minimum and Maximum Ticks
Set the `minMaxTicksOnly` property to `true` if you only want to see the two end ticks on the axis.

:::note
To display the minimum and maximum ticks only when the chart width is limited (this behavior is enabled my default),
you can use the `minMaxTicksOnlyWhenWidthIsLess` property (defaults to 250px). This helps avoid clutter in smaller visualizations while still
providing essential information.
:::

<XYWrapperWithInput
  {...axisProps()}
  inputType="checkbox"
  defaultValue={true}
  property="minMaxTicksOnly"/>


When using `minMaxTicksOnly`, you can still show grid lines by setting `minMaxTicksOnlyShowGridLines` to `true`.

<XYWrapperWithInput
  minMaxTicksOnly={true}
  {...axisProps()}
  inputType="checkbox"
  defaultValue={true}
  property="minMaxTicksOnlyShowGridLines"
  hiddenProps={{}}
/>

### Set Ticks Explicitly
You can customize the ticks displayed by providing the _Axis_ component with a number array.
The following example only shows even values for x after getting the `tickValue` array from a filter function.
```ts
function tickValues() {
  return data.filter(d => d.x % 2 == 0)
})
```
<XYWrapper {...axisProps()} tickValues={[0,2,4,6,8]} hiddenProps={{x:d=>d.x}}/>

### Hide Overlapping Ticks `1.5`
To prevent overlapping tick labels on the axis, you can use the `tickTextHideOverlapping`
property. When enabled, it hides any tick labels that would otherwise overlap with
one another based on a simple bounding box collision detection algorithm. This
ensures cleaner, more legible axes, particularly in cases where the available space
is limited or when displaying many ticks.

:::note
The algorithm used for detecting overlaps may not be accurate when a `tickTextAngle` is specified,
so results can vary depending on tick rotation.
:::

<XYWrapper {...axisProps()} numTicks={15} containerProps={{ xDomain: [0, 10000000] }} hiddenProps={{x:d=>d.x}} tickTextHideOverlapping={true}/>


## Displaying Multiple Axes
More commonly, you will want to display both an x and y axis for your graph. You can display multiple axes in an _XY Container_ like so:
<XYWrapper {...multiProps()}/>

## Displaying Axis with a Chart
You can include a chart within your _XY Container_ alongside your axes like this:
<XYWrapper {...multiProps()}
  components={[
    ...multiProps().components,
    { name: "Line", key: 'components', props: {x: d=>d.x, y: d=>d.y }}
  ]}/>

## Additional Styling: CSS Variables
The _Axis_ component supports additional styling via CSS variables that you can define for your visualization container. For example:

```css title="styles.css"
.container {
  --vis-axis-tick-label-font-size: 20px;
  --vis-axis-label-color: #1acb9a;
  --vis-axis-font-family: monospace;
  --vis-axis-tick-label-color:  #8777d9;
}
```
<XYWrapper {...axisProps()} gridLine height={150} label="Label" excludeTabs className="custom-axis"/>

<details open>
  <summary>All supported CSS variables and their default values</summary>
  <CodeBlock language="css">
{`${
  Object.entries(Axis.selectors.cssVarDefaults)
  .map(([key, value]) => `${key}: ${value};`).join('\n')}
`}</CodeBlock>
</details>

## Events
```ts
import { Axis } from '@unovis/ts'

events = {
  [Axis.selectors.tick]: {
    mouseover: (d: number | Date) => {},
    mouseout: (d: number | Date) => {}
  }
}
```
<XYWrapper {...axisProps()} excludeGraph events={{}}/>

## Component Props
<PropsTable name="VisAxis"></PropsTable>
